using System.Collections.Generic;
using System.Diagnostics;

namespace FluentParser.Expressions
{
    /// <summary>
    /// Node part of the resulting tree. This type of result is returned
    /// when ParseNode is used.
    /// </summary>
    [DebuggerDisplay("[ParsingNodeResult Expression={Expression.GetType().Name} Value={Value}]")]
    public class ParsingNodeResult
    {
        public ParsingNodeResult(IBaseExpr sourceExpr, int index)
        {
            Expression = sourceExpr;
            Index = index;
            IsSuccess = false;
            Nodes = new List<ParsingNodeResult>();
        }

        /// <summary> The expression which created this node. </summary>
        public IBaseExpr Expression { get; private set; }

        /// <summary> True if the parsing succeeded. </summary>
        public bool IsSuccess { get; set; }

        /// <summary> Index of the first character parsed. </summary>
        public int Index { get; set; }

        /// <summary> Length of the text used in the resulting value. </summary>
        public int Length { get; set; }

        /// <summary> Length of the explored length. </summary>
        public int ExploredLength { get; set; }

        /// <summary> The resulting value. </summary>
        public object Value { get; set; }

        /// <summary> Index of the last character used in the resulting value. </summary>
        public int End
        {
            get { return Index + Length; }
            set { Length = value - Index; }
        }

        /// <summary> Index of the last character parsed. </summary>
        public int ExploredEnd
        {
            get { return Index + ExploredLength; }
            set { ExploredLength = value - Index; }
        }

        /// <summary>
        /// Error accompagning this node. Has a value only when the
        /// source expression is doing error handling.
        /// </summary>
        public ParsingException Error { get; set; } 

        /// <summary> List of children attemps at parsing. </summary>
        public List<ParsingNodeResult> Nodes { get; private set; }

        /// <summary>
        /// Factory method automatically initializing a couple of variables.
        /// </summary>
        /// <param name="expr">The expression to which this node is bound.</param>
        /// <param name="context">The context of the parsing session.</param>
        /// <returns>The newly created node.</returns>
        internal ParsingNodeResult AddChild(IBaseExpr expr, GrammarContext context)
        {
            return AddChild(expr, context, Index);
        }

        /// <summary>
        /// Factory method for the creating of a node result.
        /// It automatically initializing a couple of variables
        /// (both for the parent and the child)
        /// </summary>
        /// <param name="expr">The expression to which this node is bound.</param>
        /// <param name="context">The context of the parsing session.</param>
        /// <param name="index">Position to start parsing.</param>
        /// <returns>The newly created node.</returns>
        internal ParsingNodeResult AddChild(IBaseExpr expr, GrammarContext context, int index)
        {
            ParsingNodeResult node = new ParsingNodeResult(expr, index);
            Nodes.Add(node);
            expr.ParseNode(context, node);

            if (node.ExploredEnd > ExploredEnd)
                ExploredEnd = node.ExploredEnd;
            
            if (node.IsSuccess && node.End > End)
                End = node.End;

            return node;
        }
    }
}